package com.encrypt.encrptspringbootstarter.interceptor;


import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.plugin.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.sql.Statement;
import java.util.*;

/**
 * 用于处理查询数据结果字段解密
 */
@Component
@Intercepts({ @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = { Statement.class }) })
public class ResultSetInterceptor implements Interceptor {
    private static final Logger log = LoggerFactory.getLogger(ResultSetInterceptor.class);

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 取出查询的结果
        Object resultObject = invocation.proceed();
        if (Objects.isNull(resultObject)) {
            return null;
        }
        // 基于selectList
        try {
            if (resultObject instanceof ArrayList) {
                ArrayList resultList = (ArrayList) resultObject;
                if (!CollectionUtils.isEmpty(resultList)) {
                    for (Object result : resultList) {
                        if (hasSensitive(invocation, result)) {
                            return resultObject;
                        }
                        // 逐一解密
                        this.decrypt(result);
                    }
                }
                // 基于selectOne
            } else {
                if (hasSensitive(invocation, resultObject)) {
                    return resultObject;
                }
                this.decrypt(resultObject);
            }
        } catch (Exception e) {
            log.error("解密参数处理发生异常："+e.getMessage(),e);
        }
        return resultObject;
    }

    private static boolean hasSensitive(Invocation invocation, Object result) throws InvocationTargetException, IllegalAccessException {
        Class<?> parameterObjectClass = result.getClass();
        HasSensitiveData annotation = parameterObjectClass.getAnnotation(HasSensitiveData.class);
        if (Objects.isNull(annotation)) {
            return true;
        }
        return false;
    }

    public <T> T decrypt(T result) throws IllegalAccessException {
        // 取出resultType的类
        Class<?> resultClass = result.getClass();
        Field[] declaredFields = resultClass.getDeclaredFields();
        for (Field field : declaredFields) {
            // 取出FieldPartialEncryption\FieldAllEncryption注解的字段
            FieldPartialEncryption fieldPartialEnCryption = field.getAnnotation(FieldPartialEncryption.class);
            FieldAllEncryption decryptTransaction = field.getAnnotation(FieldAllEncryption.class);
            //先处理部分解密
            if (!Objects.isNull(fieldPartialEnCryption)) {
                if (processPartialEnCrypt(result, field, fieldPartialEnCryption, declaredFields)) {
                    continue;
                }
            }
            //处理全部解密
            if (Objects.isNull(fieldPartialEnCryption) && !Objects.isNull(decryptTransaction)) {
                processALlEnCrypt(result, field);
            }
        }
        return result;
    }

    private static <T> void processALlEnCrypt(T result, Field field) throws IllegalAccessException {
        field.setAccessible(true);
        Object object = field.get(result);
        // String的解密
        if (object instanceof String) {
            String value = (String) object;
            // 对注解的字段进行逐一解密
            try {
                field.set(result, AESEncryption.decrypt(value));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private static <T> boolean processPartialEnCrypt(T result, Field field, FieldPartialEncryption fieldPartialEnCryption, Field[] declaredFields) {
        KeyWordsEnum keyWordsEnum = fieldPartialEnCryption.keyWords();
        String key= fieldPartialEnCryption.key();
        String value= fieldPartialEnCryption.value();
        if (StringUtils.isBlank(key) || StringUtils.isBlank(value)||StringUtils.isBlank(keyWordsEnum.getKeywords()) ){
            return true;
        }
        if(field.getName().equals(key)){
            List<String> keywords = Arrays.asList(keyWordsEnum.getKeywords().split(","));
            Object keyObject = null;
            try {
                field.setAccessible(true);
                keyObject = field.get(result);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
            // 暂时只实现String类型的解密
            if (keyObject instanceof String) {
                String finalObject = (String)keyObject;
                boolean b = keywords.stream().noneMatch(e -> finalObject.contains(e));
                if(b){
                    return true;
                }
            }
            Arrays.stream(declaredFields).filter(e->e.getName().equals(value)).forEach(f->{
                f.setAccessible(true);
                Object valueObject = null;
                try {
                    valueObject = f.get(result);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
                // 暂时只实现String类型的解密
                if (valueObject instanceof String) {
                    String value2 = (String) valueObject;
                    // 解密
                    try {
                        f.set(result, AESEncryption.decrypt(value2));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        return false;
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }
}